package com.hghivln.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hghivln.blog.common.exception.BlogException;
import com.hghivln.blog.common.lang.Result;
import com.hghivln.blog.entity.Blog;
import com.hghivln.blog.entity.BlogTag;
import com.hghivln.blog.entity.Tag;
import com.hghivln.blog.entity.Type;
import com.hghivln.blog.mapper.BlogMapper;
import com.hghivln.blog.mapper.BlogTagMapper;
import com.hghivln.blog.mapper.TagMapper;
import com.hghivln.blog.mapper.TypeMapper;
import com.hghivln.blog.pojo.dto.BlogDto;
import com.hghivln.blog.pojo.vo.BlogVo;
import com.hghivln.blog.service.BlogService;
import com.hghivln.blog.utils.IdWorker;
import com.hghivln.blog.utils.StringUtils;
import com.hghivln.blog.utils.PagesUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 博客表 服务实现类
 * </p>
 *
 * @author hghivln
 * @since 2021-09-11
 */
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements BlogService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private BlogTagMapper blogTagMapper;

    @Autowired
    private TypeMapper typeMapper;

    /**
     * 允许的排序列
     */
    private static final String[] SORT_COLUMNS = {"created_time", "blog_goods", "blog_read", "blog_collection", "blog_comment"};

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveBlog(BlogDto blogDto) {
        // 雪花算法生成id
        long blogId = idWorker.nextId();
        blogDto.setBlogId(blogId);
        // 把 blogDto 转换成 blog
        Blog blog = new Blog();
        // 把相同属性名的值拷贝过去
        BeanUtils.copyProperties(blogDto, blog);
        List<Tag> tagList = blogDto.getTagList();
        saveTage(blogId, tagList);
        getBaseMapper().insert(blog);
    }

    @Override
    public void deleteById(Long id) {
        getBaseMapper().delById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateBlog(BlogDto blogDto) {
        // 把 blogDto 转换成 blog
        Blog blog = new Blog();
        // 把相同属性名的值拷贝过去
        BeanUtils.copyProperties(blogDto, blog);
        getBaseMapper().updateById(blog);
        List<Tag> tagList = blogDto.getTagList();

        QueryWrapper<BlogTag> qw = new QueryWrapper<>();
        qw.eq("blog_id", blog.getBlogId());
        blogTagMapper.delete(qw);
        saveTage(blogDto.getBlogId(), tagList);
    }

    @Override
    public Result<?> loadAllLog(BlogDto blogDto) {
        QueryWrapper<Blog> qw = new QueryWrapper<>();
        qw.like(StringUtils.isNotEmpty(blogDto.getBlogTitle()), "blog_Title", blogDto.getBlogTitle());
        qw.like(blogDto.getBlogType() != null, "blog_Type", blogDto.getBlogType());
        qw.like(StringUtils.isNotEmpty(blogDto.getBlogSource()), "blog_Source", blogDto.getBlogSource());
        qw.eq("deleted", 0);
        if (!Arrays.asList(SORT_COLUMNS).contains(blogDto.getSortColumn())) {
            throw new BlogException("排序列不支持！");
        } else {
            qw.orderByDesc(blogDto.getSortColumn());
        }
        // 查询列表
        List<Blog> blogList = getBaseMapper().selectList(qw);
        if (CollectionUtils.isEmpty(blogList)) {
            return new Result<>(0L, new ArrayList<>(0));
        }

        // 查询标签
        List<Long> blogIds = blogList.stream().map(Blog::getBlogId).collect(Collectors.toList());
        List<BlogTag> blogTagList = blogTagMapper.getByBlogIds(blogIds);

        // 查询分类
        List<Long> typeIds = blogList.stream().map(Blog::getBlogType).collect(Collectors.toList());
        List<Type> typeList = typeMapper.selectBatchIds(typeIds);

        // 封装分类和标签
        List<BlogVo> blogVoList = blogList.stream().map(blog -> {
            BlogVo blogVo = new BlogVo();
            // 把 blog转换成 blogVo
            BeanUtils.copyProperties(blog, blogVo);
            return blogVo;
        }).peek(bv -> {
            // 根据分类id取出分类列表中对应的数据
            Type type = typeList.stream().filter(t -> t.getTypeId().equals(bv.getBlogType())).findFirst().orElse(new Type());
            bv.setTypeName(type.getTypeName());
        }).peek(bv -> {
            // 根据博客id取出标签
            List<String> tagNameList = blogTagList.stream().filter(bt -> bt.getBlogId().equals(bv.getBlogId())).map(BlogTag::getTagName).collect(Collectors.toList());
            bv.setTagNameList(tagNameList);
        }).collect(Collectors.toList());
        Page pages = PagesUtils.getPages(blogDto.getPage(), blogDto.getLimit(), blogVoList);
        return new Result<>(pages.getTotal(), pages.getRecords());
    }

    @Override
    public BlogVo getInfo(Long id) {
        Blog blog = getBaseMapper().selectById(id);
        // 阅读数 +1
        blog.setBlogRead(blog.getBlogRead()+1);
        getBaseMapper().updateById(blog);
        // 将blog 转变为 blogVo
        BlogVo blogVo = new BlogVo();
        BeanUtils.copyProperties(blog, blogVo);
        // 查询分类
        Type type = typeMapper.selectById(blog.getBlogType());
        blogVo.setTypeName(type.getTypeName());
        return blogVo;
    }

    @Override
    public Blog getUpdate(Long id) {
        QueryWrapper<Blog> qw = new QueryWrapper<>();
        qw.select("blog_id", "blog_title", "blog_image", "blog_content", "blog_type", "blog_remark");
        qw.eq("blog_id", id);
        return getBaseMapper().selectOne(qw);
    }

    @Override
    public Result<?> getBlogByType(BlogDto blogDto) {
        QueryWrapper<Blog> qw = new QueryWrapper<>();
        qw.eq("deleted", 0);
        qw.eq("blog_type",blogDto.getBlogType());
        if (!Arrays.asList(SORT_COLUMNS).contains(blogDto.getSortColumn())) {
            throw new BlogException("排序列不支持！");
        } else {
            qw.orderByDesc(blogDto.getSortColumn());
        }
        // 查询列表
        List<Blog> blogList = getBaseMapper().selectList(qw);
        if (CollectionUtils.isEmpty(blogList)) {
            return new Result<>(0L, new ArrayList<>(0));
        }
        // 查询分类
        Type type = typeMapper.selectById(blogDto.getBlogType());

        List<BlogVo> blogVoList = blogList.stream().map(blog -> {
            BlogVo blogVo = new BlogVo();
            // 把 blog转换成 blogVo
            BeanUtils.copyProperties(blog, blogVo);
            blogVo.setTypeName(type.getTypeName());
            return blogVo;
        }).collect(Collectors.toList());

        Page pages = PagesUtils.getPages(blogDto.getPage(), blogDto.getLimit(), blogVoList);
        return new Result<>(pages.getTotal(), pages.getRecords());
    }

    @Override
    public List<Blog> getTimeLine(Integer index) {
        return getBaseMapper().getTimeLine(index);
    }

    @Override
    public Result<?> getMeta(Long blogId) {
        Blog blog = getBaseMapper().selectById(blogId);
        // 将blog 转变为 blogVo
        BlogVo blogVo = new BlogVo();
        BeanUtils.copyProperties(blog, blogVo);
        return new Result<>(blogVo);
    }

    private void saveTage(Long blogId, List<Tag> tagList) {
        // 判断标签列表是否为空,如果不为空就存库
        if (!CollectionUtils.isEmpty(tagList)) {
            // 取出需要存到标签表里的标签  filter(e -> e.getId() == null) 表为新建的标签
            // 过滤出 tagList集合中 id == null的值再转换成 list集合，并赋给 saveList集合 。
            // (Collectors.toList():转换成list集合。steam():把一个源数据，可以是集合，数组，I/O channel， 产生器generator 等，转化成流。)
            List<Tag> saveList = tagList.stream().filter(e -> e.getId() == null).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(saveList)) {
                saveList.forEach(tag -> tagMapper.insert(tag));
            }
            // 存关联表 转换成关联对象
            List<BlogTag> blogTagList = tagList.stream().map(tag -> {
                BlogTag blogTag = new BlogTag();
                blogTag.setId(idWorker.nextId());
                blogTag.setTagId(tag.getId());
                blogTag.setBlogId(blogId);
                blogTag.setTagName(tag.getName());
                return blogTag;
            }).collect(Collectors.toList());
            // 存库
            blogTagList.forEach(blogTag -> {
                blogTagMapper.insert(blogTag);
            });
        }
    }
}
